/**
  ******************************************************************************
  * @file           
  * @author         古么宁
  * @brief          101 协议栈初始化相关
  ******************************************************************************
  *
  * COPYRIGHT(c) 2019 GoodMorning
  *
  ******************************************************************************
  */
/* Includes ---------------------------------------------------*/
#include <string.h>
#include "iec10x.h"
#include "iec10x_link.h"
#include "iec10x_event.h"
#include "iec10x_sync.h"
#include "iec10x_telesgnl.h"
#include "iec10x_debug.h"

/* Private type  ------------------------------------------------------------*/
/* Private macro ------------------------------------------------------------*/
/* Private variables --------------------------------------------------------*/
/* Global variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/


#if (!ENABLE_IEC101_SLAVE)
	void iec101slv_unbalance_period(iec10x_t * bus) {}
	void iec101slv_balance_period(iec10x_t * bus)   {}
#else
/**
  * @brief    平衡 101 从机定时判断
  * @param    bus     : 主机总线对象
  * @return   
*/
void iec101slv_balance_period(iec10x_t * bus)
{
	uint16_t txlen;

	if (bus->ctrling == 1 && iec_timestamp - bus->ctrlt > bus->ctrl_wait) {
		/* 遥控处于被选择阶段，出现超时 */
		bus->ctrling = 0;
		memset(bus->ctrl.argv,0, sizeof(struct iec_do));
		iec10x_warn(bus,"select ctrl timeout\r\n");
	}

	if (bus->busy) {
		if ( iec_timestamp - bus->onlinet > bus->t1) { 
			/* 超时重发，如果已经超过最大次重发无响应，重连 */
			bus->onlinet = iec_timestamp;
			if (++bus->iec101.resend > bus->iec101.resendmax) {
				iec101mst_conncet(bus);
				bus->iec101.resend = 0 ;
			}
			else {
				if (bus->txbuf[0] == 0x10) 
					txlen = (4 + bus->iec101.lnaddrlen) ;
				else 
					txlen = (bus->txbuf[1] + 4 + 2);
				/* 报文解析打印 */
				iec10x_warn(bus,"no respond[0x%x],resend packet.\r\n",bus->busy);
				IEC101_PACKET_INFO(bus,bus->txbuf,txlen,IEC_TX_PKT);
				bus->haltx(bus->txbuf,txlen);
			}
		}
		return ;
	}

	if (bus->event.next != &bus->event) {
		iec10xslv_event_pro(bus);
		return ;
	}
	
	if (bus->iec101.todo) {
		iec_fn_t func = bus->iec101.todo;
		bus->iec101.todo = NULL;
		func(bus);
	}
	else
	if (!bus->operate.todo){
		if(iec_timestamp - bus->periodt > bus->data_period) {
			/* 周期主动上送数据优先级最低，更新时间戳 */
			bus->periodt = iec_timestamp;
			iec10xslv_peridic_summon(bus);
		}
	}
}




/**
  * @brief    非平衡 101 从机定时判断
  * @param    bus     : 主机总线对象
  * @return   
*/
void iec101slv_unbalance_period(iec10x_t * bus)
{
	if (bus->ctrling == 1 && iec_timestamp - bus->ctrlt > bus->ctrl_wait) {
		/* 遥控超时 */
		bus->ctrling = 0;
		memset(bus->ctrl.argv,0, sizeof(struct iec_do));
		iec10x_warn(bus,"select ctrl timeout\r\n");
	}

	if (bus->iec101.todo) {
		void (*func)(struct iec10x * this) ;
		func = bus->iec101.todo ;
		bus->iec101.todo = NULL;
		func(bus);
	}
}

#endif /* #if (!ENABLE_IEC101_SLAVE) */




#if (!ENABLE_IEC101_MASTER)
	void iec101mst_period(iec10x_t * bus){}
#else
/**
  * @brief    101 主机总线周期处理
  * @param    bus        : 主机总线对象
  * @return   don't care
*/
void iec101mst_period(iec10x_t * bus)
{
	uint16_t txlen;
	if (!bus->connected) {
		/* 如果未连接，则定时发送启动链路报文 */
		if (iec_timestamp - bus->onlinet > bus->t3) {
			bus->onlinet = iec_timestamp ;
			iec101mst_conncet(bus);
		}
		return  ;
	}

	if (bus->busy) {
		if ( iec_timestamp - bus->onlinet > bus->t1) { 
			/* 超时重发，如果已经超过最大次重发无响应，重连 */
			bus->onlinet = iec_timestamp;//更新时间戳
			if (++bus->iec101.resend > bus->iec101.resendmax) {
				iec101mst_conncet(bus);
				bus->iec101.resend = 0 ;
			}
			else {
				if (bus->txbuf[0] == 0x10) 
					txlen = (4 + bus->iec101.lnaddrlen) ;
				else 
					txlen = (bus->txbuf[1] + 4 + 2);
				iec10x_warn(bus,"no respond[0x%x],resend packet.\r\n",bus->busy);
				/* 报文解析打印 */
				IEC101_PACKET_INFO(bus,bus->txbuf,txlen,IEC_TX_PKT);
				bus->haltx(bus->txbuf,txlen);
			}
		}
		return ;
	}

	if (bus->ctrl.todo) {
		/* 当前有遥控操作则执行操作 */
		bus->ctrl.todo(bus);
		return ;
	}
	else
	if (bus->event.next != &bus->event && !bus->ctrling) {
		/* 在非遥控状态下处理突发事件请求 */
		iec10xmst_event_pro(bus);
		bus->onlinet = iec_timestamp ;
		return ;
	}
	else
	if (bus->operate.todo) {
		/* 当前有总召/对时/电度流程操作则执行操作 */
		bus->operate.todo(bus);
		return ;
	}

	#if (0)//(ENABLE_FILE_TRANS)
		else if (bus->fs.func) {
			/* 有正在执行的操作 */
			bus->onlinet = iec_timestamp;
			bus->fs.func(bus);
			return ;
		}
	#endif
	
	if (iec_timestamp - bus->periodt > bus->data_period) {
		/* 进行定时总召唤 */
		iec10x_msg(bus,"summon period.\r\n");
		bus->periodt = iec_timestamp ;
		iec10xmst_summon(bus,IEC_GRP_ALL);
	}
	else
	if (iec_timestamp - bus->synct > bus->sync_period) {
		/* 对时命令 */
		bus->synct = iec_timestamp ;
		iec10xmst_sync(bus);
	}
	else
	if(iec_timestamp - bus->onlinet > bus->t3) {
		bus->onlinet = iec_timestamp;
		if (bus->mode & IEC_BALANCE){ 
			iec101_heartbeat(bus);
		}
		else {
			int FCB  = (bus->iec101.FCB == 0);
			bus->iec101.FCB = FCB;
			iec101_protocol_send(bus,NULL,0,MSTCTRL(MASTER_DATA_2,1,FCB));
		}
	}
}
#endif /** #if (!ENABLE_IEC101_MASTER) */



#if (!ENABLE_IEC104_SLAVE)
	void iec104slv_period(iec10x_t * bus) {}
#else
/**
  * @brief    iec104 从机总线周期处理
  * @param    bus        : 主机总线对象
  * @return   don't care
*/
void iec104slv_period(iec10x_t * bus)
{
	if (!bus->connected) {
		return  ;
	}

	if (bus->ctrling) {
		if (bus->ctrl.todo) {
			bus->onlinet = iec_timestamp;
			bus->ctrl.todo(bus);
			return ;
		}
		else
		if (bus->ctrling == 1 && iec_timestamp - bus->ctrlt > bus->ctrl_wait) {
			/* 遥控超时 */
			bus->ctrling = 0;
			memset(&bus->ctrl,0, sizeof(struct iec_do));
			iec10x_warn(bus,"select ctrl timeout\r\n");
		}
	}

	if (bus->event.next != &bus->event) {
		/* 有突发事件优先处理突发事件数据包 */
		iec10xslv_event_pro(bus);
		bus->onlinet = iec_timestamp;
		return ;
	}

	if (bus->operate.todo) {
		/* 有总召/对时/电度流程操作，判断滑动窗口，还有剩余则执行操作 */
		if (bus->iec104.txnums - bus->iec104.txcheck <= bus->iec104.k) {
			bus->onlinet = iec_timestamp;
			bus->operate.todo(bus);
			return ;
		}
	}
	#if (ENABLE_FILE_TRANS)
		else
		if (bus->fs.todo) {
			/* 有文件传输流程操作 */
			if (bus->iec104.txnums - bus->iec104.txcheck <= bus->iec104.k) {
				bus->onlinet = iec_timestamp;
				bus->fs.todo(bus);
				return ;
			}
		}
	#endif

	if (bus->busy || bus->iec104.txcheck != bus->iec104.txnums) {
		/* 有未确认的帧，即总线仍在传输数据 */
		if (iec_timestamp - bus->onlinet > bus->t1) {
			iec10x_warn(bus,"remote timeout[0x%x].\r\n",bus->busy);
			iec104_disconnect(bus);
			bus->halrst(bus);
		}
		return ;
	}

	if (iec_timestamp - bus->periodt > bus->data_period) {
		/* 周期主动上送数据优先级最低，更新时间戳 */
		bus->periodt = iec_timestamp;
		iec10xslv_peridic_summon(bus);
		return ;
	}
	else
	if (iec_timestamp - bus->onlinet > bus->t3) {
		/* 空闲状态下发送测试帧报文 */
		iec104_heartbeat(bus);
	}
}
#endif /** #if (!ENABLE_IEC104_SLAVE) */


#if (!ENABLE_IEC104_MASTER)
	void iec104mst_period(iec10x_t * bus){}
#else
/**
  * @brief    iec104 主机总线周期处理
  * @param    bus        : 主机总线对象
  * @return   don't care
*/
void iec104mst_period(iec10x_t * bus)
{
	if (!bus->connected) {
		/* 如果未连接，则定时发送启动链路报文 */
		if (iec_timestamp - bus->onlinet > 3000) {
			bus->onlinet = iec_timestamp ;
			iec104mst_conncet(bus);
		}
		return  ;
	}

	if (bus->iec104.rxnums != bus->iec104.rxcheck){
		/* 到时更新滑动窗口 */
		if (iec_timestamp - bus->onlinet > bus->t2) {
			bus->iec104.rxcheck = bus->iec104.rxnums ;
			iec104_protocol_send(bus,0,0,1);
			return ;
		}
	}

	if (bus->event.next != &bus->event && !bus->ctrling) {
		/* 在非遥控状态下处理突发事件请求 */
		iec10xmst_event_pro(bus);
		bus->onlinet = iec_timestamp ;
		return ;
	}

	if (bus->operate.todo) {
		/* 当前有操作则执行操作 */
		bus->operate.todo(bus);
		return ;
	}
	else
	if (bus->ctrl.todo) {
		/* 当前有遥控操作则执行操作 */
		bus->ctrl.todo(bus);
		return ;
	}
	#if (ENABLE_FILE_TRANS)
		else
		if (bus->fs.todo) {
			/* 有正在执行的操作 */
			if (bus->iec104.txnums - bus->iec104.txcheck <= bus->iec104.k) {
				bus->onlinet = iec_timestamp;
				bus->fs.todo(bus);
				return ;
			}
		}
	#endif

	if (bus->busy || bus->ctrling) {
		/* 总线忙，判断无响应超时 */
		if (iec_timestamp - bus->onlinet > bus->t1) {
			iec104_disconnect(bus);
			bus->halrst(bus);
		}
	}
	else 
	if (iec_timestamp - bus->periodt > bus->data_period){
		bus->periodt = iec_timestamp;
		iec10xmst_summon(bus,IEC_GRP_ALL);
	}
	else
	if (iec_timestamp - bus->synct  > bus->sync_period) {
		iec10xmst_sync(bus);
	}
	else
	if (iec_timestamp - bus->onlinet > bus->t3) {
		/* 空闲状态下发送测试帧报文 */
		iec104_heartbeat(bus);
	}
}
#endif /** #if (!ENABLE_IEC104_MASTER) */
